/*
 * Copyright (C) 2022, KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

#include "side-bar-application.h"

#include <QQmlContext>
#include <QWindow>
#include <QDebug>
#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QPainterPath>
#include <QQuickWindow>
#include <QThread>
#include <QOpenGLContext>
#include <QSurfaceFormat>

#include "global-settings.h"
#include "shortcut-model-manager.h"
#include "screen-monitor.h"
#include "hand-gesture-helper.h"
#include "date-time-utils.h"
#include "window-blur-helper.h"
#include "app-manager.h"
#include "sidebar-window-helper.h"
#include "sidebar-view.h"
#include "notification-window.h"
#include "popup-notification-window.h"
#include "notification-model.h"
#include "tablet-popup-view.h"
#include "status-bar-view.h"
#include "right-hand-gesture-view.h"
#include "event-track.h"
#include "shortcuts-window.h"
#include "sidebar-dbus-service.h"

//注册托盘
#define  TRAY_ICON           ":/icon/kylin-tool-box.svg"
#define  TRAY_NULL_ICON      ":/icon/kylin-tool-box-null.svg"
#define  SETTING_ICON        ":/icon/application-menu.svg"

using namespace Sidebar;

SideBarApplication::SideBarApplication(const QString &appId, int &argc, char **argv) : QtSingleApplication(appId, argc, argv)
{
    if (!isRunning()) {
        //load translations.
        auto translator = new QTranslator(this);
        try {
            if (!translator->load(QString(TRANSLATION_FILE_DIR) + "/ukui-sidebar_" + QLocale::system().name() + ".qm")) {
                throw -1;
            }
            SideBarApplication::installTranslator(translator);
        } catch (...) {
            qWarning() << "Load translations file" << QLocale::system().name() << "failed!";
        }

        createSystray();
        startSidebar();

        // 第一次启动时，解析命令行参数
        parseCommand(SideBarApplication::arguments().join(" ").toUtf8(), true);
        connect(this, &QtSingleApplication::messageReceived, [=](const QString &msg) {
            this->parseCommand(msg, true);
        });
    } else {
        parseCommand(SideBarApplication::arguments().join(" ").toUtf8(), false);
    }
}

SideBarApplication::~SideBarApplication()
{
    if (m_trayIconMenu) {
        delete m_trayIconMenu;
        m_trayIconMenu = nullptr;
    }

    if (m_popupNotificationWindow) {
        delete m_popupNotificationWindow;
        m_popupNotificationWindow = nullptr;
    }
}

void SideBarApplication::initPublicObjects()
{
    GlobalSettings::globalInstance();
    ScreenMonitor::getInstance();
    HandGestureHelper::getInstance();
    SidebarWindowHelper::instance();
}

void SideBarApplication::loadQML()
{
    QQmlContext *rootContext = UkuiQuick::SharedEngineView::sharedEngine()->rootContext();
    rootContext->setContextProperty("isOpenGLEnv", false);
    rootContext->setContextProperty("dateTimeUtils", new Sidebar::DateTimeUtils(this));
    rootContext->setContextProperty("appManager", AppManager::getInstance());
    rootContext->setContextProperty("screenMonitor", ScreenMonitor::getInstance());

    const bool isLiteMode = GlobalSettings::globalInstance()->getValue(IS_LITE_MODE).toBool();
    rootContext->setContextProperty("isLiteMode", isLiteMode);

    initShortcut();
    // 更新特效开关变量
    rootContext->setContextProperty("isOpenGLEnv", !isLiteMode && (QQuickWindow::sceneGraphBackend() == ""));

    initSidebar();
    initPopupWindow();

    if (!isLiteMode) {
        loadTabletWindows();
        connect(GlobalSettings::globalInstance(), &GlobalSettings::valueChanged, this, [this] (const QString &key) {
            if (key == TABLET_MODE) {
                loadTabletWindows();
            }
        });
    }

    connect(GlobalSettings::globalInstance(), &GlobalSettings::valueChanged, this, [rootContext] (const QString &key) {
        if (key == IS_LITE_MODE) {
            const bool isLiteMode = GlobalSettings::globalInstance()->getValue(key).toBool();
            rootContext->setContextProperty("isLiteMode", isLiteMode);
            rootContext->setContextProperty("isOpenGLEnv", !isLiteMode && (QQuickWindow::sceneGraphBackend() == ""));
        }
    });
    qDebug() << "loadQML isOpenGLEnv:" << (QQuickWindow::sceneGraphBackend() == "") << QQuickWindow::sceneGraphBackend();
}

void SideBarApplication::initSidebar()
{
    m_sidebarWindow = new SidebarView;

    m_sidebarWindow->rootContext()->setContextProperty("isNotificationCenter", false);
    m_sidebarWindow->rootContext()->setContextProperty("groupModel", UkuiNotification::NotificationCenterWindow::globalGroupModel());
    m_sidebarWindow->rootContext()->setContextProperty("sourceModel", UkuiNotification::NotificationModel::instance());
    m_sidebarWindow->rootContext()->setContextProperty("handGestureHelper", HandGestureHelper::getInstance());
    m_sidebarWindow->init();

    //屏幕右侧响应左划动作
    RightHandGestureView *handGestureView = new RightHandGestureView;
    handGestureView->init();

    connect(UkuiNotification::NotificationCenterWindow::globalGroupModel(), &QAbstractItemModel::rowsInserted, [this] {
        if (m_sidebarWindow && m_notificationCenterWindow) {
            if ((!m_sidebarWindow->isVisible()) && (!m_notificationCenterWindow->isVisible())) {
                updateSystrayIcon(false);
            }
        }
    });

    connect(m_sidebarWindow, &SidebarView::visibleChanged, UkuiNotification::NotificationModel::instance(),
            &UkuiNotification::NotificationModel::storePopupNotification);
}

void SideBarApplication::initShortcut()
{
    m_shortcutsWindow = new ShortcutsWindow;
}

void SideBarApplication::initNotificationCenter()
{
    m_notificationCenterWindow = new UkuiNotification::NotificationCenterWindow;
    m_notificationCenterWindow->rootContext()->setContextProperty("isNotificationCenter", true);

    m_notificationCenterWindow->init();

    connect(m_notificationCenterWindow, &UkuiNotification::NotificationCenterWindow::visibleChanged, this, [=] {
        updateSystrayIcon(true);
    });

    //状态栏（响应下划动作）
    StatusBarView *statusBarView = new StatusBarView;
    statusBarView->init();
}

void SideBarApplication::initPopupWindow()
{
    m_popupNotificationWindow = new UkuiNotification::PopupNotificationWindow;

    connect(m_sidebarWindow, &SidebarView::visibleChanged,
            m_popupNotificationWindow, [=] (const bool isSidebarShow) {
        m_popupNotificationWindow->updateWindowPosition(isSidebarShow, m_sidebarWindow->width());
    });

    m_popupNotificationWindow->loadQML();
}

void SideBarApplication::loadTabletWindows()
{
    bool isTabletMode = GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool();
    if (isTabletMode) {
        if (!m_notificationCenterWindow) {
            initNotificationCenter();
        }

        if (!m_tabletPopupView) {
            initTabletPopupWindow();
        }
    } else {
        if (m_tabletPopupView) {
            m_tabletPopupView->close();
            //m_tabletPopupView->deleteLater();
            delete m_tabletPopupView;
            m_tabletPopupView = nullptr;
        }

        if (m_notificationCenterWindow) {
            disconnect(m_notificationCenterWindow, nullptr, this, nullptr);
            m_notificationCenterWindow->close();
            //m_notificationCenterWindow->deleteLater();
            delete m_notificationCenterWindow;
            m_notificationCenterWindow = nullptr;
        }
    }
}

void SideBarApplication::initTabletPopupWindow()
{
    m_tabletPopupView = new UkuiNotification::TabletPopupView;
}

void SideBarApplication::parseCommand(const QString &msg, bool isPrimary)
{
    QCommandLineParser parser;

    QCommandLineOption sidebarState({"S", "state"}, QObject::tr("Show the current state of the sidebar."));
    QCommandLineOption sidebarShow({"s", "show"}, QObject::tr("There are two options, 'notify' and 'control'."), "option");
    QCommandLineOption sidebarQuit({"q", "quit"}, QObject::tr("Quit sidebar."));

    parser.addOption(sidebarState);
    parser.addOption(sidebarShow);
    parser.addOption(sidebarQuit);

    if (isPrimary) {
        parser.parse(msg.split(" "));

        if (parser.isSet(sidebarState)) {
            //state

        } else if (parser.isSet(sidebarShow)) {
            //show
            if (parser.value(sidebarShow) == "notify") {
                if (!m_notificationCenterWindow) {
                    qWarning() << "The sidebar is not running or there is an error, please restart 'ukui-sidebar'";
                    return;
                }
                m_notificationCenterWindow->activeNotificationCenter(true);

            } else if (parser.value(sidebarShow) == "control") {
                requestSidebar(Active);
            }

        } else if (parser.isSet(sidebarQuit)) {
            SideBarApplication::quit();
        }

    } else {
        // 检查命令行参数是否匹配，选项parse为true，但是命令选项可能为空
        if (parser.parse(arguments()) && !parser.optionNames().isEmpty()) {
            // sidebar主程序只接受 S, s, q 三个类别的命令
            this->sendMessage(msg);

        } else {
            QCommandLineOption helpOption = parser.addHelpOption();
            QCommandLineOption versionOption = parser.addVersionOption();

            parser.parse(arguments());
            if (parser.isSet(versionOption)) {
                parser.showVersion();
            } else {
                if (!parser.unknownOptionNames().isEmpty()) {
                    qDebug() << "Unknown options:" << parser.unknownOptionNames();
                }
                parser.showHelp();
            }
        }
    }
}

void SideBarApplication::registerItems()
{
    const char uri[] = "org.ukui.sidebar.core";
    SidebarWindowDefineModule::defineModules(uri, 1, 0);
    // 公用部分 包括自定义图标item
    qmlRegisterType<Sidebar::SettingMonitor>("org.ukui.sidebar.core", 1, 0, "SettingMonitor");
    //qmlRegisterType<Sidebar::WindowBlurHelper>("org.ukui.sidebar.core", 1, 0, "WindowBlurHelper");
    qmlRegisterUncreatableType<UkuiShortcut::Color>("org.ukui.sidebar.core", 1, 0, "PluginColorRole", "Enum");
    qmlRegisterUncreatableType<Sidebar::EventTrack>("org.ukui.sidebar.core", 1, 0, "EventTrack", "Only attached prop.");

    // 控制中心: 注册类用于在qml访问枚举变量
    qmlRegisterUncreatableType<UkuiShortcut::PluginMetaType>("org.ukui.sidebar.shortcut.core", 1, 0, "ShortcutPlugin", "Enum");

    // 通知中心专用部分
    qmlRegisterUncreatableType<UkuiNotification::NotificationItem>("org.ukui.notification.core", 1, 0, "NotificationItem", "Enum");

    //注册元类型 用于信号与槽，与qml交互
    qRegisterMetaType<UkuiShortcut::Color::ColorRole>("Color::ColorRole");
    qRegisterMetaType<UkuiShortcut::StatusInfo::MenuItem>("StatusInfo::MenuItem");
    qRegisterMetaType<UkuiShortcut::PluginMetaType::Action>("PluginMetaType::Action");
    qRegisterMetaType<UkuiShortcut::PluginMetaType::PluginType>("PluginMetaType::PluginType");
    qRegisterMetaType<UkuiShortcut::PluginMetaType::SystemMode>("PluginMetaType::SystemMode");
}

//注册托盘、创建托盘菜单
void SideBarApplication::createSystray()
{
    int intervalTime = 100, registerCount = 0;
    while (!QSystemTrayIcon::isSystemTrayAvailable() && registerCount <= 5) {
        ++registerCount;
        intervalTime *= 2;
        QThread::msleep(intervalTime);
    }

    m_trayIcon = new QSystemTrayIcon(this);
    if (nullptr == m_trayIcon) {
        qWarning() << "Allocate space trayIcon failed";
        return;
    }

    m_trayIconMenu = new QMenu;
    auto open = new QAction(QObject::tr("Open"), m_trayIconMenu);
    auto openSetUp = new QAction(QIcon::fromTheme("document-page-setup-symbolic", QIcon(SETTING_ICON)),
                                 tr("Set up notification center"), m_trayIconMenu);

    m_trayIconMenu->addAction(open);
    m_trayIconMenu->addAction(openSetUp);

    m_trayIcon->setIcon(QIcon::fromTheme("ukui-tool-symbolic", QIcon(TRAY_ICON)));
    m_trayIcon->setContextMenu(m_trayIconMenu);
    m_trayIcon->setToolTip(tr("NotificationCenter"));
    m_trayIcon->setVisible(true);

    connect(open, &QAction::triggered, [this] {
        requestSidebar(Active);
    });
    connect(openSetUp, &QAction::triggered, [] {
        AppManager::getInstance()->launchAppWithArguments("/usr/share/applications/ukui-control-center.desktop", {"-m", "Notice"}, "ukui-control-center");
    });
    connect(m_trayIcon, &QSystemTrayIcon::activated, [this] {
        if (m_shortcutsWindow) {
            m_shortcutsWindow->activeShortcutsWindow(!m_shortcutsWindow->isVisible());
        }
    });
}

void SideBarApplication::startSidebar()
{
    SideBarApplication::registerItems();

    initPublicObjects();
    loadQML();

    // 初始化侧边栏dbus接口
    new Sidebar::SidebarDbusService(this);
}

void SideBarApplication::updateSystrayIcon(bool clearRedPoint)
{
    if (!m_trayIcon) {
        return;
    }

    if (clearRedPoint) {
        m_trayIcon->setToolTip(tr("NotificationCenter"));
        m_trayIcon->setIcon(QIcon::fromTheme("ukui-tool-symbolic", QIcon(TRAY_ICON)));

    } else {
        m_trayIcon->setToolTip(tr("%1 Notifications").arg(UkuiNotification::NotificationCenterWindow::globalGroupModel()->rowCount(QModelIndex())));
        m_trayIcon->setIcon(QIcon::fromTheme("ukui-tool-box-null-symbolic", QIcon(TRAY_NULL_ICON)));
    }
}

void SideBarApplication::requestSidebar(SideBarApplication::Request request)
{
    if (!m_sidebarWindow) {
        return;
    }

    bool isActivate = false;
    switch (request) {
        case Active: {
            isActivate = !m_sidebarWindow->isVisible();
            m_sidebarWindow->activeWindow(isActivate);
            break;
        }
        case Show: {
            isActivate = true;
            m_sidebarWindow->activeWindow(true);
            break;
        }
        case Hide: {
            m_sidebarWindow->activeWindow(false);
            break;
        }
        case DirectlyHide: {
            m_sidebarWindow->setWindowVisible(false);
            break;
        }
        default:
            break;
    }

    if (isActivate) {
        updateSystrayIcon();
    }
}

void SideBarApplication::requestNotificationCenter(SideBarApplication::Request request)
{
    if (!m_sidebarWindow) {
        return;
    }

    switch (request) {
        case Active: {
            m_sidebarWindow->setVisible(!m_sidebarWindow->isVisible());
            break;
        }
        case Show: {
            m_sidebarWindow->show();
            break;
        }
        case Hide: {
            m_sidebarWindow->hide();
            break;
        }
        default:
            break;
    }
}
